	PAGE	,132			; 						 ;AN000;
;	SCCSID = @(#)ifsfdos.asm	1.0 87/08/29					 ;AN000;
TITLE	IFSFUNC DOS CALLBACK ROUTINES - Routines for ifs				 ;AN000;
NAME	IFSFDOS 									 ;AN000;
;***********************************************************************************	 ;AN000;
;											 ;AN000;
; IFS DOS Callback Routines								 ;AN000;
;											 ;AN000;
; IFSFDOS										 ;AN000;
;											 ;AN000;
; REVISION HISTORY:									 ;AN000;
;	A000 - Original version 4.00	AUG 1987   DCR - 96				 ;AN000;
;	A001 - DCR 47 Get disk/device pause status AUG '87 RG                       ;AN000;
;	A002 - PTM 2610 Time/date problems	   DEC '87 RG                       ;AN000;
;											 ;AN000;
; LOC - 										 ;AN000;
;											 ;AN000;
;***********************************************************************************	 ;AN000;
											 ;AN000;
.xlist											 ;AN000;
.xcref											 ;AN000;
INCLUDE IFSFSYM.INC									 ;AN000;
INCLUDE IFSSYM.INC									 ;AN000;
INCLUDE DOSSYM.INC									 ;AN000;
INCLUDE DEVSYM.INC									 ;AN000;
.cref											 ;AN000;
.list											 ;AN000;
.sall											 ;AN000;
											 ;AN000;
AsmVars <IBM, INSTALLED, DEBUG, PATHGEN>						 ;AN000;
											 ;AN000;
IFSSEG	SEGMENT BYTE PUBLIC 'IFSSEG'                                                     ;AN000;
IFSSEG	ENDS										 ;AN000;
											 ;AN000;
include dosseg.asm									 ;AN000;
											 ;AN000;
DATA		SEGMENT WORD PUBLIC 'DATA'                                               ;AN000;
	; DOSGROUP data 								 ;AN000;
	Extrn	YEAR:WORD
	Extrn	YRTAB:BYTE
	Extrn	MONTAB:BYTE
DATA		ENDS									 ;AN000;
											 ;AN000;
IFSSEG	SEGMENT BYTE PUBLIC 'IFSSEG'                                                     ;AN000;
	ASSUME	SS:DOSGROUP,CS:IFSSEG							 ;AN000;
											 ;AN000;
	;IFS Data									 ;AN000;
											 ;AN000;
	Extrn	IFSFUNC_FLAGS:WORD							 ;AN000;
	Extrn	DOSCALL@:DWORD								 ;AN000;
	Extrn	fAssign:BYTE								 ;AN001;
	Extrn	fPrint:BYTE								 ;AN001;
											 ;AN000;
											 ;AN000;
BREAK <SET_IFS_DOSCALL@ - prep for ifs dos requests to come to ifsfunc> 		 ;AN000;
;************************************************************************************	 ;AN000;
;											 ;AN000;
; SET_IFS_DOSCALL@									 ;AN000;
;											 ;AN000;
;Called by:										 ;AN000;
;     IFSFUNCINIT									 ;AN000;
;											 ;AN000;
; Routines called:									 ;AN000;
;	none										 ;AN000;
;											 ;AN000;
; Inputs:										 ;AN000;
;	   DS-ifsseg									 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;	replace ifs_doscall@ addresses in all ifs driver headers with			 ;AN000;
;	ifsfunc address 								 ;AN000;
;											 ;AN000;
; Outputs:										 ;AN000;
;	none										 ;AN000;
;											 ;AN000;
; Notes: all preserved									 ;AN000;
;											 ;AN000;
;************************************************************************************	 ;AN000;
											 ;AN000;
	procedure   SET_IFS_DOSCALL@,NEAR						 ;AN000;
ASSUME	DS:IFSSEG									 ;AN000;
	TEST	IFSFUNC_FLAGS,NO_IFS_DRIVERS						 ;AN000;
	JZ	SID_20									 ;AN000;
	transfer ifs_1000								 ;AN000;
SID_20: 										 ;AN000;
	SaveReg <AX,BX,ES,DI,SI>							 ;AN000;
	MOV	AH,Get_In_Vars			; Get ptr to ifs hdr chain		 ;AN000;
	INT	21h				; es:bx -> sysinitvars			 ;AN000;
	LES	DI,ES:[BX.SYSI_IFS]		; es:di -> 1st ifs driver		 ;AN000;
	SaveReg <ES,DI> 								 ;AN000;
	LES	DI,ES:[DI.IFS_DOSCALL@] 						 ;AN000;
	MOV	WORD PTR [DOSCALL@],DI							 ;AN000;
	MOV	WORD PTR [DOSCALL@+2],ES						 ;AN000;
	RestoreReg <DI,ES>			; 1st driver addr			 ;AN000;
	MOV	SI,OFFSET IFSFUNC_DOSCALL@						 ;AN000;
SID_40: 					; *** loop here on ifs_doscall@ fixing	 ;AN000;
	MOV	WORD PTR ES:[DI.IFS_DOSCALL@],SI					 ;AN000;
	MOV	WORD PTR ES:[DI.IFS_DOSCALL@+2],DS					 ;AN000;
	LES	DI,ES:[DI.IFS_NEXT]		; check next fs driver			 ;AN000;
	CMP	DI,NULL_PTR			; if ptr null, end of ifs drivers	 ;AN000;
	JNE	SID_40									 ;AN000;
	MOV	AX,ES									 ;AN000;
	CMP	AX,NULL_PTR								 ;AN000;
	JNE	SID_40									 ;AN000;
											 ;AN000;
SID_1000:										 ;AN000;
	RestoreReg <SI,DI,ES,BX,AX>							 ;AN000;
	return										 ;AN000;
											 ;AN000;
EndProc SET_IFS_DOSCALL@								 ;AN000;
											 ;AN000;
											 ;AN000;
											 ;AN000;
BREAK <IFSFUNC_DOSCALL@ - DOS Callbacks>						 ;AN000;
;************************************************************************************	 ;AN000;
;											 ;AN000;
; IFSFUNC_DOSCALL@									 ;AN000;
;											 ;AN000;
;Called by:										 ;AN000;
;     IFS Drivers									 ;AN000;
;											 ;AN000;
; Routines called:									 ;AN000;
;	none										 ;AN000;
;											 ;AN000;
; Inputs:										 ;AN000;
;	   SS-dosgroup									 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;											 ;AN000;
; Outputs:										 ;AN000;
;	none										 ;AN000;
;											 ;AN000;
; Notes: none preserved 								 ;AN000;
;											 ;AN000;
;************************************************************************************	 ;AN000;
											 ;AN000;
	procedure   IFSFUNC_DOSCALL@,FAR						 ;AN000;
											 ;AN000;
	CMP	AH,33									 ;AN001;
	JNE	ID_20									 ;AN000;
	CALL	DOS_RETURN_ASSIGN_MODE							 ;AN001;
	JMP	SHORT ID_1000								 ;AN001;
ID_20:											 ;AN001;
	CMP	AH,34									 ;AN000;
	JNE	ID_40									 ;AN000;
	CALL	DOS_TO_NET_DATE 							 ;AN000;
	JMP	SHORT ID_1000								 ;AN000;
ID_40:											 ;AN000;
	CMP	AH,35									 ;AN000;
	JNE	ID_100									 ;AN000;
	CALL	NET_TO_DOS_DATE 							 ;AN000;
	JMP	SHORT ID_1000								 ;AN000;
ID_100: 										 ;AN000;
	CALL	CS:[DOSCALL@]							      ;AN000;
											 ;AN000;
ID_1000:										 ;AN000;
	RET										 ;AN000;
											 ;AN000;
											 ;AN000;
EndProc IFSFUNC_DOSCALL@								 ;AN000;


BREAK <DOS_RETURN_ASSIGN_MODE -- Return Assign Mode>					 ;AN000;

;************************************************************************************
;
; DOS_RETURN_ASSIGN_MODE
;
; Called by:  IFSFUNC_DOSCALL@
;
; Routines called:   None
;
; Inputs:
;	    BL = macro type
;		 3 - device
;		 4 - drive
; Function:
;	If macro type = 3 (network printer) THEN
;	   BX = fPrint .AND. 1
;	Elseif macro type = 4 (network disk) THEN
;	   BX = fAssign .AND. 1
;	Else set error_invalid_function
;
; Output:
;	Carry clear - BH = mode (0 - off, 1 - on)
;	Carry set   - AL error code
;
; Notes:  This routine needed only for UNC file system.  This is the
;	  only FS that supports pause.
;
;************************************************************************************

	Procedure   DOS_RETURN_ASSIGN_MODE,NEAR 					 ;AN001;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN001;
											 ;AN001;
	CMP	BL,3			; if (type == drive)				 ;AN001;
	JZ	DRAM_20 								 ;AN001;
	CMP	BL,4									 ;AN001;
	JNZ	DRAM_60 								 ;AN001;
	MOV	BH,fAssign		;    t = fAssign;				 ;AN001;
	JMP	Short DRAM_40		; else						 ;AN001;
DRAM_20:				; if (type == print)				 ;AN001;
	MOV	BH,fPrint		;    t = fPrint;				 ;AN001;
DRAM_40:										 ;AN001;
	AND	BH,1			;   return t&1; 				 ;AN001;
	transfer ifs_990		; go to general good ret in util		 ;AN001;
											 ;AN001;
DRAM_60:										 ;AN001;
	MOV	AL,error_invalid_function						 ;AN001;
	transfer ifs_980		; go to general bad ret in util 		 ;AN001;
											 ;AN001;
EndProc DOS_RETURN_ASSIGN_MODE								 ;AN001;

BREAK <DOS_TO_NET_DATE	-- Convert dos date/time to network date>			 ;AN000;

;************************************************************************************
;
; DOS_TO_NET
;
; Called by:  IFSFUNC_DOSCALL@
;
; Routines called:   None
;
; Inputs:										 ;AN000;
;	DX = MS-DOS Date								 ;AN000;
;	CX = MS-DOS Time								 ;AN000;
; Function:										 ;AN000;
;	Convert DOS Date Time to Network date						 ;AN000;
; Outputs:										 ;AN000;
;	DX:CX = Seconds since 1-1-70							 ;AN000;
; No other registers Revised								 ;AN000;
;
;************************************************************************************

FOURYEARS	= (3*365) + 366 	; Days in four years				 ;AN000;

	procedure DOS_TO_NET_DATE,NEAR							 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
	OR	AL,AL			; check where to get dos date/time		 ;AN002;
	JNZ	DTND_20 								 ;AN002;
	CallInstall DATE16,MultDOS,13	; Get local date/time				 ;AN000;
	MOV	CX,DX									 ;AN000;
	XCHG	AX,DX									 ;AN000;
											 ;AN000;
DTND_20:										 ;AN002;
	PUSH	DS									 ;AN000;
	PUSH	SS									 ;AN000;
	POP	DS									 ;AN000;
ASSUME	DS:DOSGROUP									 ;AN000;
	PUSH	[YEAR]			; The routines in DOS (in particular		 ;AN000;
					;	GET_DATE) do not like [YEAR]		 ;AN000;
					;	getting changed by the call		 ;AN000;
					;	to SETYEAR.				 ;AN000;
	PUSH	SI									 ;AN000;
	PUSH	BX									 ;AN000;
	PUSH	AX									 ;AN000;
	PUSH	CX									 ;AN000;
	PUSH	DX									 ;AN000;
											 ;AN000;
	MOV	CL,9									 ;AN000;
	SHR	DX,CL			; Year to DL					 ;AN000;
	MOV	CX,DX			; Year in CX (CL)				 ;AN000;
	POP	DX									 ;AN000;
	AND	DX,1FFH 		; Mask off year 				 ;AN000;
	SHL	DX,1									 ;AN000;
	SHL	DX,1									 ;AN000;
	SHL	DX,1			; Month in DH					 ;AN000;
	SHR	DL,1									 ;AN000;
	SHR	DL,1									 ;AN000;
	SHR	DL,1			; Right justify day in DL			 ;AN000;
	CallInstall SetYear,MultDOS,27	; Set [YEAR] and # days in FEB			 ;AN000;
	SHR	CX,1									 ;AN000;
	SHR	CX,1			; Divide year by 4, chuck remainder		 ;AN000;
	MOV	AX,FOURYEARS								 ;AN000;
	MOV	BX,DX			; Get DX out of way				 ;AN000;
	MUL	CX			; # days in AX					 ;AN000;
	MOV	CL,BYTE PTR [YEAR]							 ;AN000;
	AND	CL,3			; Get remainder from / by 4			 ;AN000;
	MOV	SI,OFFSET DOSGROUP:YRTAB						 ;AN000;
	MOV	DX,AX									 ;AN000;
	SHL	CX,1			; Two entries/year				 ;AN000;
	CallInstall DSum,MultDOS,28,<AX>,<SI>						 ;AN000;
	MOV	CL,BH			; Month 					 ;AN000;
	DEC	CX			; Make 0 indexed				 ;AN000;
	MOV	SI,OFFSET DOSGROUP:MONTAB						 ;AN000;
	CallInstall DSum,MultDOS,28,<AX>,<AX>						 ;AN000;
	MOV	CL,BL			; day of month					 ;AN000;
	DEC	CX			; Make 0 indexed				 ;AN000;
	ADD	CX,DX			; CX is days since 1-1-80			 ;AN000;
;											 ;AN000;
; The following three instructions implement this:					 ;AN000;
;											 ;AN000;
;		CX * 15180H sec/day = (CX * 5180H) + (CX * 10000H)			 ;AN000;
;											 ;AN000;
	MOV	AX,5180h								 ;AN000;
	MUL	CX			; (DX:AX) = days * 5180h			 ;AN000;
	ADD	DX,CX			; (DX:AX) = days * 15180h = seconds		 ;AN000;
											 ;AN000;
	ADD	AX,0A600H								 ;AN000;
	ADC	DX,012CEH		; Bias by # seconds from 1-1-70 to		 ;AN000;
					; 1-1-80 (12CEA600H)				 ;AN000;
	POP	BX			; Get DOS time					 ;AN000;
	PUSH	AX									 ;AN000;
	PUSH	DX			; Save date seconds				 ;AN000;
	PUSH	BX									 ;AN000;
	MOV	CL,11									 ;AN000;
	SHR	BX,CL			; BX is hours					 ;AN000;
	MOV	AX,60									 ;AN000;
	MUL	BX			; AX hours converted to minutes 		 ;AN000;
					;    5A0H min/day so DX = 0			 ;AN000;
	POP	BX									 ;AN000;
	PUSH	BX									 ;AN000;
	AND	BX,7FFH 		; Mask off hours				 ;AN000;
	MOV	CL,5									 ;AN000;
	SHR	BX,CL			; BX is minutes 				 ;AN000;
	ADD	AX,BX			; AX is minutes 				 ;AN000;
	MOV	BX,60									 ;AN000;
	MUL	BX			; DX:AX is hours:min converted to sec		 ;AN000;
	POP	BX									 ;AN000;
	AND	BX,1FH			; BX is seconds/2				 ;AN000;
	SHL	BX,1			; BX is seconds 				 ;AN000;
	ADD	AX,BX									 ;AN000;
	ADC	DX,0									 ;AN000;
	MOV	CX,AX			; DX:CX is DOS time in seconds			 ;AN000;
	POP	BX									 ;AN000;
	POP	SI			; BX:SI is DOS Date in seconds			 ;AN000;
	ADD	CX,SI									 ;AN000;
	ADC	DX,BX			; DX:CX is NET time				 ;AN000;
	POP	AX									 ;AN000;
	POP	BX									 ;AN000;
	POP	SI									 ;AN000;
	POP	[YEAR]									 ;AN000;
	POP	DS									 ;AN000;
	return										 ;AN000;
											 ;AN000;
EndProc DOS_TO_NET_DATE 								 ;AN000;
											 ;AN000;
; Inputs:										 ;AN000;
;	DX:CX = Seconds since 1-1-70							 ;AN000;
; Function:										 ;AN000;
;	Convert Network date to DOS Date Time						 ;AN000;
;    NOTE: WARNING!!!!!!!								 ;AN000;
;	This routine WILL NOT convert network times > 92CEA5FFH 			 ;AN000;
;	(7FFFFFFF + 12CEA600). If such a time is encountered this			 ;AN000;
;	routine returns 1-1-80 0:0:0.							 ;AN000;
; Outputs:										 ;AN000;
;	DX = MS-DOS Date								 ;AN000;
;	CX = MS-DOS Time								 ;AN000;
; No other registers Revised								 ;AN000;
											 ;AN000;
	procedure NET_TO_DOS_DATE,NEAR							 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
	SUB	CX,0A600H								 ;AN000;
	SBB	DX,012CEH		; UnBias by # seconds from 1-1-70 to		 ;AN000;
					; 1-1-80 (12CEA600H)				 ;AN000;
	JNC	GO_ON									 ;AN000;
	; Date is before 1-1-80 							 ;AN000;
TO_BIG_LITTLE_TIME:									 ;AN000;
	XOR	DX,DX									 ;AN000;
	MOV	CX,DX	; Set 1-1-80 0:0:0						 ;AN000;
	return										 ;AN000;
											 ;AN000;
GO_ON:											 ;AN000;
	TEST	DX,8000H		; Check for high bit				 ;AN000;
	JNZ	TO_BIG_LITTLE_TIME							 ;AN000;
	PUSH	DS									 ;AN000;
	PUSH	SS									 ;AN000;
	POP	DS									 ;AN000;
ASSUME	DS:DOSGROUP									 ;AN000;
	PUSH	[YEAR]			; The routines in DOS (in particular		 ;AN000;
					;	GET_DATE) do not like [YEAR]		 ;AN000;
					;	getting changed by the call		 ;AN000;
					;	to SETYEAR.				 ;AN000;
	PUSH	AX									 ;AN000;
	PUSH	BX									 ;AN000;
	PUSH	SI									 ;AN000;
	PUSH	BP									 ;AN000;
	XCHG	AX,CX			; DX:AX # seconds				 ;AN000;
	MOV	SI,0A8C0h		; (si) = seconds in a half day			 ;AN000;
					;    15180H/2					 ;AN000;
;											 ;AN000;
; NOTE: The following DIV is the reason we can't convert times with the                  ;AN000;
;	high bit set (after they're unbiased by 1-1-80 - 1-1-70).                        ;AN000;
;	If we tried one it MIGHT overflow. The cutoff is				 ;AN000;
;	actually (A8C0 * FFFF) + A8BF = A8BFFFFF but we choose a smaller		 ;AN000;
;	number (7FFFFFFF) because it's easier to test for. 7FFFFFFF =                    ;AN000;
;	about 68 years from 1-1-80 which is 1-1-2048.					 ;AN000;
;											 ;AN000;
	DIV	SI			; (AX) = 2*days 				 ;AN000;
					; (CX) = half-day remainder			 ;AN000;
	MOV	BX,DX									 ;AN000;
	XOR	DX,DX									 ;AN000;
	MOV	CX,DX									 ;AN000;
	SHR	AX,1			; DX:AX = days					 ;AN000;
	JNC	NTDD1			; didn't shift off a bit, no extra rem           ;AN000;
	ADD	BX,0A8C0h		; did shift bit, adjust remainder		 ;AN000;
	ADC	CX,0			;   by extra 1/2 day of seconds 		 ;AN000;
											 ;AN000;
	;DX:AX is # days since 1-1-80							 ;AN000;
	;CX:BX is seconds into that day 						 ;AN000;
NTDD1:											 ;AN000;
	PUSH	DX									 ;AN000;
	PUSH	AX									 ;AN000;
	MOV	DX,CX									 ;AN000;
	MOV	AX,BX									 ;AN000;
	MOV	CX,60			; 60 sec/min					 ;AN000;
	DIV	CX									 ;AN000;
	;AX is min, DX(DL) is secs							 ;AN000;
	DIV	CL			; 60 min/hr					 ;AN000;
	;AH is Min, AL is hrs								 ;AN000;
	SHR	DL,1			; Div seconds by 2				 ;AN000;
	AND	DL,1FH			; DL is seconds/2				 ;AN000;
	MOV	DH,AH			; Copy min to DH				 ;AN000;
	MOV	CL,5									 ;AN000;
	SHL	AH,CL			; Low 3 bits of min in high 3 bits		 ;AN000;
	OR	DL,AH			; DL is now low byte of time			 ;AN000;
	MOV	CL,3									 ;AN000;
	SHR	DH,CL			; High 3 bits of min to low 3 bits		 ;AN000;
	AND	DH,7									 ;AN000;
	MOV	CL,3									 ;AN000;
	SHL	AL,CL			; Hours to high 5 bits				 ;AN000;
	AND	AL,0F8H 								 ;AN000;
	OR	DH,AL			; DX is now DOS time				 ;AN000;
	MOV	CX,DX									 ;AN000;
	POP	AX									 ;AN000;
	POP	DX			; DX:AX days since 1-1-80			 ;AN000;
	PUSH	CX			; Stash time					 ;AN000;
	MOV	CX,FOURYEARS								 ;AN000;
	DIV	CX			; AX # four year increments			 ;AN000;
					; DX remainder days				 ;AN000;
	SHL	AX,1									 ;AN000;
	SHL	AX,1									 ;AN000;
	SHL	AX,1			; Mult by 8 (AX # 1/2 years)			 ;AN000;
	MOV	CX,AX									 ;AN000;
	MOV	SI,OFFSET DOSGROUP:YRTAB						 ;AN000;
	CallInstall DSlide,MultDOS,29,<AX>,<AX> 					 ;AN000;
	SHR	CX,1			; 1/2 years to whole years			 ;AN000;
	JNC	SK									 ;AN000;
	ADD	DX,200			; Extra 1/2 year				 ;AN000;
SK:											 ;AN000;
	CallInstall SetYear,multDOS,27							 ;AN000;
	PUSH	CX									 ;AN000;
	MOV	CL,1			; At least at first month in year		 ;AN000;
	MOV	SI,OFFSET DOSGROUP:MONTAB						 ;AN000;
	CallInstall DSlide,MultDOS,29,<AX>,<AX> 					 ;AN000;
	INC	DX			; Days start at 1				 ;AN000;
	POP	AX									 ;AN000;
	MOV	CH,CL									 ;AN000;
	; DL is day, CH is month, AL is year						 ;AN000;
	SHL	AL,1			; Year to high 7 bits				 ;AN000;
	AND	AL,0FEH 								 ;AN000;
	MOV	AH,CH									 ;AN000;
	MOV	CL,3									 ;AN000;
	SHR	AH,CL			; High bit of month to bit 0			 ;AN000;
	AND	AH,1									 ;AN000;
	OR	AH,AL			; AH is high byte of date			 ;AN000;
	AND	DL,1FH			; Day is low 5 bits				 ;AN000;
	MOV	CL,5									 ;AN000;
	SHL	CH,CL			; Low 3 bits of month to high 3 bits		 ;AN000;
	AND	CH,0E0H 								 ;AN000;
	OR	DL,CH									 ;AN000;
	MOV	DH,AH			; Date in DX					 ;AN000;
	POP	CX			; Time to CX					 ;AN000;
	POP	BP									 ;AN000;
	POP	SI									 ;AN000;
	POP	BX									 ;AN000;
	POP	AX									 ;AN000;
	POP	[YEAR]									 ;AN000;
	POP	DS									 ;AN000;
	return										 ;AN000;
											 ;AN000;
EndProc NET_TO_DOS_DATE 								 ;AN000;
											 ;AN000;
IFSSEG	ENDS										 ;AN000;
END											 ;AN000;
